package copyfile;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author xiaplus 2014-2-22 上午11:42:53
 */
public class RWdemo implements Runnable {
	String threadnunmid;
	long begin;
	long end;
	FileChannel readchannel;
	FileChannel writechannel;
	LinkedHashMap<String, List> writeMap;

	
	public void copyNioDemo(){
		//Files.copy(source, target, options);
	}
	
	public RWdemo(LinkedHashMap<String, List> writeMap, String threadnunmid,
			FileChannel readchannel, FileChannel writechannel, long begin,
			long end) {
		this.writeMap = writeMap;
		this.threadnunmid = threadnunmid;
		this.begin = begin;
		this.end = end;
		this.readchannel = readchannel;
		this.writechannel = writechannel;
	}

	public RWdemo() {
	}

	// **************************************************************************************
	public static void main(String[] args) throws FileNotFoundException,
			IOException, InterruptedException {
		String a = "C:\\code\\studio2010\\shutdownerrorwindows\\Debug\\shutdownerrorwindows.dll";
		String b = "C:\\shutdownerrorwindows.dll";
		// String a = "D:\\x\\a.iso";
		// String b = "D:\\x\\b.iso";
		long before = System.currentTimeMillis();
		MutilThreadRW(a, b);
		System.out.println("MillTime : "
				+ (double) (System.currentTimeMillis() - before) + "毫秒");
	}

	// ***********************************************************************************
	public static void MutilThreadRW(String sourcePath, String targetPath)
			throws FileNotFoundException, IOException, InterruptedException {
		LinkedHashMap<String, List> writeMap = new LinkedHashMap<String, List>();
		File f = new File(sourcePath);
		RandomAccessFile raf = new RandomAccessFile(targetPath, "rw");
		raf.setLength(f.length());
		final long ModuleSize = 1024 * 1024 * 4;// 额定读写大小4M
		File files = new File(sourcePath); // 源文件
		File filet = new File(targetPath); // 目标文件
		long size = files.length(); // 文件总大小
		int copycount = (int) (size / ModuleSize); // 获取读、写
		long lastModuleSize = size % ModuleSize;// 最后一个线程负责的大小
		if (lastModuleSize != 0) {
			copycount = copycount + 1;
		}

		String[] marks = new String[copycount];
		for (int x = 0; x < copycount; x++) {
			marks[x] = x + getRandomPW();
		}
		long countSize = ModuleSize; // 每块分割大小<每次读写的大小>
		long lontemp = countSize; // 初始读、写大小
		FileChannel readchannel = new RandomAccessFile(files, "r").getChannel(); // 得到映射读文件的通道
		FileChannel writechannel = new RandomAccessFile(filet, "rw")
				.getChannel(); // 得到映射写文件的通道
		ExecutorService executorService = Executors.newFixedThreadPool(128);
		for (int i = 0; i < copycount; i++) {
			if (i < (copycount - 1)) {
				executorService.execute(new RWdemo(writeMap, marks[i],
						readchannel, writechannel, ModuleSize * i, ModuleSize));
			} else {
				executorService.execute(new RWdemo(writeMap, marks[i],
						readchannel, writechannel, ModuleSize * i,
						lastModuleSize));
			}
		}
		executorService.shutdown();
		executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);// 所有线程执行完毕才进入下一步
		writeUtil(readchannel, writechannel, marks, writeMap, ModuleSize,
				lastModuleSize);
	}

	// ***********************************************************************************
	public static void writeUtil(FileChannel readchannel,
			FileChannel writechannel, String[] arr,
			LinkedHashMap<String, List> writeMap, long ModuleSize,
			long lastModuleSize) throws IOException {
		System.out.println("线程数目" + arr.length);
		int threadnumbers = arr.length;
		for (int i = 0; i < threadnumbers; i++) {
			List list = (List) writeMap.get(arr[i]);
			MappedByteBuffer readFile;
			MappedByteBuffer writeFile;
			Long begin;
			Long end;
			try {
				readFile = (MappedByteBuffer) list.get(0);
				begin = (Long) list.get(1);
				end = (Long) list.get(2);
				writeFile = writechannel.map(FileChannel.MapMode.READ_WRITE,
						begin, end); // 每次写目标文件都重新构造对象
				writeFile.put(readFile);
			} catch (Exception e) {
				System.err
						.println("×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××");
				if (i < threadnumbers - 1) {
					readFile = readchannel.map(FileChannel.MapMode.READ_ONLY,
							ModuleSize * i, ModuleSize); // 每次读源文件都重新构造对象
					writeFile = writechannel.map(
							FileChannel.MapMode.READ_WRITE, ModuleSize * i,
							ModuleSize); // 每次写目标文件都重新构造对象
					writeFile.put(readFile);
				} else {
					readFile = readchannel.map(FileChannel.MapMode.READ_ONLY,
							ModuleSize * i, lastModuleSize); // 每次读源文件都重新构造对象
					writeFile = writechannel.map(
							FileChannel.MapMode.READ_WRITE, ModuleSize * i,
							lastModuleSize); // 每次写目标文件都重新构造对象
					writeFile.put(readFile);
				}
			}
			System.out.println("写完" + i);
		}
	}

	// ********************************************************************************
	public static String getRandomPW() {
		Random ran1 = new Random();
		int length = (int) (ran1.nextFloat() * 20 + 1);
		String pwChar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		String password = "";
		Random rdm = new Random(System.currentTimeMillis());
		for (int i = 0; i < length; i++) {
			int index = rdm.nextInt() % pwChar.length();
			if (index < 0) {
				index = 0 - index;
			}
			password = password + pwChar.charAt(index);
		}
		return password;
	}

	// ***********************************************************************************
	public void run() {
		try {
			MappedByteBuffer readFile = readchannel.map(
					FileChannel.MapMode.READ_ONLY, begin, end); // 每次读源文件都重新构造对象
			List list = new ArrayList();
			list.add(readFile);
			list.add(begin);
			list.add(end);
			writeMap.put(this.threadnunmid, list);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
